package com.gillion.grule.client.components;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gillion.grule.client.core.*;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.common.collect.Lists;
import org.mvel2.MVEL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component("JDBC")
public class JDBCComponent extends ExecuteComponent {
    private static final Logger LOGGER = LoggerFactory.getLogger(JDBCComponent.class);
    private static final String RETURNTYPE = "returnType";

    public <T> T execute(String express, Context context) {
        LOGGER.info("规则引擎 调用jdbc配置：" + express);

        JSONObject jSONObject = JSON.parseObject(express);
        List<String> expressParams = (List)jSONObject.get("params");
        List<String> params = Lists.newArrayList();
        String url = null;
        String userName = null;
        String passWord = null;
        String sqlExpress = "";
        String sqlParam = null;
        String sqlResult = null;

        List<DataSourceClient> dataSourceClients = context.getDataSources();
        for (DataSourceClient dataSourceClient : dataSourceClients) {
            for (SqlConfigClient sqlConfigClient : dataSourceClient.getSqlConfigClient()) {
                if (jSONObject.get("sqlName").equals(sqlConfigClient.getSqlName())) {
                    url = dataSourceClient.getUrl();
                    userName = dataSourceClient.getUsername();
                    passWord = dataSourceClient.getPassword();
                    sqlExpress = sqlConfigClient.getSqlExpress();
                    sqlParam = sqlConfigClient.getSqlParam();
                    sqlResult = sqlConfigClient.getSqlResult();
                }
            }
        }

        String sql = sqlExpress;
        JSONArray jSONArray = JSON.parseArray(sqlParam);
        LOGGER.info("参数配置列表为：", sqlParam);


        int i;


        for (i = 0; i < expressParams.size(); i++) {
            Object obj = expressParams.get(i);
            if (obj == null) {
                params.add(null);
            }
            else if (obj instanceof String && jSONObject.get("type") != null) {
                if (expressParams.get(i).toString().indexOf("'") > -1) {
                    params.add(expressParams.get(i).toString());
                } else {
                    params.add(MVEL.eval("'" + expressParams.get(i).toString() + "'", context).toString());
                }
            } else {
                params.add(MVEL.eval(expressParams.get(i).toString(), context).toString());
            }
        }


        for (i = 0; i < jSONArray.size(); i++) {
            if (params.get(i) == null) {
                sql = sql.replaceAll("'#\\{" + (String)jSONArray.get(i) + "\\}'", "null");
            } else {
                sql = sql.replaceAll("#\\{" + (String)jSONArray.get(i) + "\\}", params.get(i));
            }
        }

        if (sql.startsWith("call")) {
            return execute(url, userName, passWord, sqlResult, sql, context, jSONArray.toJavaList(String.class), expressParams);
        }
        return execute(url, userName, passWord, sqlResult, sql, context, (jSONObject
                .get("sqlColumn") == null || jSONObject.get("sqlColumn").equals("-") || jSONObject.get("sqlColumn").equals("")) ? "" : jSONObject.get("sqlColumn").toString());
    }











    public <T> T execute(String url, String userName, String passWord, String sqlResult, String sql, Context context, String entityColumn) {
        String type = getDriverType(url);
        Connection connection = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            if ("mysql".equals(type)) {
                Class.forName("com.mysql.jdbc.Driver");
            }
            if ("oracle".equals(type)) {
                Class.forName("oracle.jdbc.driver.OracleDriver");
            }
            connection = DriverManager.getConnection(url, userName, passWord);
            stmt = connection.createStatement();
            LOGGER.info("执行sql语句：" + sql);

            rs = stmt.executeQuery(sql);
            JSONObject jSONObject = JSON.parseObject(sqlResult);
            if (jSONObject.get("returnType") != null && "unit".equals(jSONObject.get("returnType"))) {
                if (rs.next()) {
                    return (T)rs.getObject((String)jSONObject.get("returnColumn"));
                }
            } else if ("entity".equals(jSONObject.get("returnType"))) {
                if (rs.next()) {
                    Map<Object, Object> map = new HashMap<>();
                    for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
                        map.put(rs.getMetaData().getColumnName(i), rs.getObject(i));
                    }
                    if (entityColumn != null && !"".equals(entityColumn)) {
                        return (T)rs.getObject(entityColumn);
                    }
                    return (T)map;
                }
            } else if ("list".equals(jSONObject.get("returnType"))) {
                List<Map<String, Object>> list = new ArrayList<>();
                while (rs.next()) {
                    Map<String, Object> map = new HashMap<>();
                    for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
                        map.put(rs.getMetaData().getColumnName(i), rs.getObject(i));
                    }
                    list.add(map);
                }
                return (T)list;
            }

        } catch (ClassNotFoundException e) {
            LOGGER.error("数据库驱动类未找到", e);
        } catch (SQLException e) {
            LOGGER.error("sql执行失败", e);
        } finally {
            close(rs, stmt, connection);
        }
        return null;
    }

    public <T> T execute(String url, String userName, String passWord, String sqlResult, String sql, Context context, List<String> paramsConfigList, List<String> expressParams) {
        String type = getDriverType(url);
        Connection connection = null;
        CallableStatement stmt = null;
        ResultSet rs = null;


        try {
            if ("mysql".equals(type)) {
                Class.forName("com.mysql.jdbc.Driver");
            }
            if ("oracle".equals(type)) {
                Class.forName("oracle.jdbc.driver.OracleDriver");
            }
            connection = DriverManager.getConnection(url, userName, passWord);
            stmt = connection.prepareCall("{" + sql + "}");
            if (paramsConfigList != null && paramsConfigList.size() > 0)
            {
                for (int j = 0; j < paramsConfigList.size(); j++) {
                    String[] str = paramsConfigList.get(j).toString().split(":");
                    if (str.length < 2) {
                        LOGGER.error("入参配置错误，当前入参配置为：" + paramsConfigList.get(j).toString());
                    }
                    if (str.length == 3) {
                        if (str[2].equals("String")) {
                            stmt.setString(j, expressParams.get(j).toString());
                            stmt.registerOutParameter(j, 12);
                        } else if (str[2].equals("Integer")) {
                            stmt.setInt(j, Integer.valueOf(expressParams.get(j).toString()).intValue());
                            stmt.registerOutParameter(j, 4);
                        }

                    } else if (str[0].equals("in") && str[1].equals("String")) {
                        stmt.setString(j, expressParams.get(j).toString());
                    } else if (str[0].equals("in") && str[1].equals("Integer")) {
                        stmt.setInt(j, Integer.valueOf(expressParams.get(j).toString()).intValue());
                    } else if (str[0].equals("out") && str[1].equals("String")) {
                        stmt.registerOutParameter(j, 12);
                    } else if (str[0].equals("out") && str[1].equals("Integer")) {
                        stmt.registerOutParameter(j, 4);
                    }
                }
            }

            stmt.execute();
            for (int i = 0; i < paramsConfigList.size(); i++) {
                String[] str = paramsConfigList.get(i).toString().split(":");
                if (str.length > 2 || str[0].equals("out")) {
                    return (T)stmt.getObject(i);
                }
            }
        } catch (Exception e) {
            LOGGER.error("存储过程执行失败", e);
        } finally {
            close(rs, stmt, connection);
        }
        return null;
    }

    public void close(ResultSet rs, Statement stmt, Connection connection) {
        try {
            if (rs != null) {
                rs.close();
            }
            if (stmt != null) {
                stmt.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            LOGGER.error("数据库连接关闭失败", e);
        }
    }

    public String getDriverType(String url) {
        String type = "";
        if (url.indexOf("jdbc:mysql") > -1) {
            type = "mysql";
        } else if (url.indexOf("jdbc:oracle") > -1) {
            type = "oracle";
        } else {
            LOGGER.error("数据库连接错误！");
        }
        return type;
    }

    public static void main(String[] args) {
        String i = "111:001";
        String[] x = i.split(":");
        System.out.println(x);
    }
}
